﻿
namespace Patterns4Net.Tests.ArchitectureExplorer.ViewModels
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using Caliburn.Micro;
    using Moq;

    /// <summary>
    /// Base class for ViewModels tests provide creation of basic mock objects.
    /// </summary>
    public class ViewModelTestBase
    {
        protected IEventAggregator EventAggregator { get; private set; }

        protected IList<object> MessagesSent { get; private set; }

        protected void SetUpMocks()
        {
            this.MessagesSent = new List<object>();
            this.EventAggregator = new EventAggregatorDecorator(this.MessagesSent, new EventAggregator());
        }

        protected void AssertPublishedMessage(Func<object, bool> assert = null)
        {
            SafeAssert.That(
                () => assert(this.MessagesSent.First()),
                (this.MessagesSent.FirstOrDefault() ?? "null") + " does not conform to the assertion.");
        }

        protected void AssertPublishedMessage<T>(Func<T, bool> assert = null) where T : class
        {
            SafeAssert.That(
                () => this.MessagesSent.First() is T,
                typeof(T).Name + " should have been published.");            

            if (assert != null)
            {
                SafeAssert.That(
                    () => assert(this.MessagesSent.First() as T),
                    typeof(T).Name + " does not contain expected data.");
            }

            this.MessagesSent.Remove(this.MessagesSent.First());
        }

        private class EventAggregatorDecorator : IEventAggregator
        {
            private readonly IList<object> published;

            private IEventAggregator inner;

            public EventAggregatorDecorator(IList<object> published, EventAggregator inner)
            {
                this.published = published;
                this.inner = inner;
            }

            public void Publish<T>(T message)
            {
                this.published.Add(message);
                this.inner.Publish(message);
            }

            public void Subscribe(object instance)
            {
                this.inner.Subscribe(instance);
            }

            public void Unsubscribe(object instance)
            {
                this.inner.Unsubscribe(instance);
            }
        }
    }
}
